package com.lrkj.framework.websocket;

import com.alibaba.fastjson.JSONObject;
import com.lrkj.common.utils.spring.SpringUtils;
import com.lrkj.framework.websocket.dao.MessageDao;
import com.lrkj.framework.websocket.entity.WSMessage;
import com.lrkj.framework.websocket.model.WebSocketResult;
import com.lrkj.framework.websocket.model.WebSocketUserProp;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class WebSocketUtil {
    private static ConcurrentMap<String, WebSocketSession> webSocketMap = new ConcurrentHashMap<>();
    private static ConcurrentMap<String, Set<String>> loginUserMap = new ConcurrentHashMap<>();
    private static ConcurrentMap<String, WebSocketUserProp> userPropMap = new ConcurrentHashMap<>();

    public static synchronized void online(WebSocketSession session) {
        WebSocketUserProp userProp = WebSocketUserProp.fromSession(session);
        if (!loginUserMap.containsKey(userProp.getId())) {
            loginUserMap.put(userProp.getId(), new HashSet<String>());
        }
        loginUserMap.get(userProp.getId()).add(getSessionKey(session));
        webSocketMap.put(getSessionKey(session), session);
        userPropMap.put(getSessionKey(session), WebSocketUserProp.fromSession(session));

        sendLastMessage(userProp);
    }

    private static void sendLastMessage(WebSocketUserProp userProp) {
        List<WSMessage> messages = SpringUtils.getBean(MessageDao.class).queryNotSendMessage(userProp.getId(), userProp.getClient().name());
        for (WSMessage message : messages) {
            sendMessageTo(userProp.getId(), message);
        }
    }

    private static String getSessionKey(WebSocketSession socketSession) {
        return socketSession.getRemoteAddress().getHostString() + socketSession.getRemoteAddress().getPort();
    }

    public static synchronized void offline(WebSocketSession session) {
        WebSocketUserProp userProp = WebSocketUserProp.fromSession(session);
        String key = getSessionKey(session);
        if (loginUserMap.containsKey(userProp.getId())) {
            if (loginUserMap.get(userProp.getId()).contains(key)) {
                loginUserMap.get(userProp.getId()).remove(key);
            }
            if (loginUserMap.get(userProp.getId()).size() < 1) {
                loginUserMap.remove(userProp.getId());
            }
        }
        webSocketMap.remove(key);
    }

    public static synchronized Integer getOnlineCount() {
        return webSocketMap.size();
    }

    public static void sendMessageToAll(WSMessage message) {
        for (String key : webSocketMap.keySet()) {
            WebSocketSession item = webSocketMap.get(key);
            if (message.getClient().equals(userPropMap.get(key).getClient().name())) {
                try {
                    item.sendMessage(new TextMessage(handleResult(message)));
                } catch (IOException e) {
                    LogFactory.getLog(WebSocketUtil.class).error(ExceptionUtils.getStackTrace(e));
                }
            }
        }
    }

    public static boolean sendMessageTo(String userId, WSMessage message) {
        boolean send = false;
        if (loginUserMap.containsKey(userId)) {
            for (String id : loginUserMap.get(userId)) {
                if (webSocketMap.containsKey(id) && webSocketMap.get(id).isOpen() && message.getClient().equals(userPropMap.get(id).getClient().name())) {
                    try {
                        webSocketMap.get(id).sendMessage(new TextMessage(handleResult(message)));
                        send = true;
                    } catch (IOException e) {
                        LogFactory.getLog(WebSocketUtil.class).error(ExceptionUtils.getStackTrace(e));
                    }
                }
            }
        }
        if (!send) {
            SpringUtils.getBean(MessageDao.class).cacheNotSendMessage(message, userId);
        }
        return send;
    }


    public static void receive(String jsonMessage, WebSocketSession session) {
        //TODO 处理客户端发送的消息,目前不需要处理,之后需要处理了在添加
    }


    public static String handleError(Throwable e) {
        WebSocketResult result = new WebSocketResult();
        result.setSuccess(false);
        result.setMessage(e.getMessage());
        return JSONObject.toJSONString(result);
    }

    public static String handleResult(WSMessage message) {
        WebSocketResult result = new WebSocketResult();
        result.setSuccess(message.getSuccess() != null ? message.getSuccess() : true);
        result.setData(message);
        return JSONObject.toJSONString(result);
    }
}
